﻿
using Common.JWT;
using Microsoft.Owin.Security.Infrastructure;
using System;
using System.Threading.Tasks;

namespace OAuthServerApi
{
    public class CustomRefreshAccessTokenProvider : AuthenticationTokenProvider
    {
        public CustomRefreshAccessTokenProvider()
        {
        }
        public override async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            try
            {
                using (var db = new DbOAuthHelper())
                {
                    //owin-access-token
                    var access = context.OwinContext.Get<OAuthToken>(OwinEnvType.AccessToken);
                    //owin-refresh-token
                    var refreshToken = context.OwinContext.Get<OAuthToken>(OwinEnvType.RefreshToken);
                    //owin-grant-code
                    var grantCode = context.OwinContext.Get<OAuthCode>(OwinEnvType.GrantCode);
                    var responseType = grantCode == null ? 0 : grantCode.ResponseType;
                    //生成票据
                    var ticket = refreshToken == null ? context.SerializeTicket() : refreshToken.Ticket;
                    //生成token
                    var tokenValue = string.Concat(access.AccessToken, ".", ticket);
                    var token = JwtHelper.MD5(tokenValue, 32);
                    access.RefreshToken = token;
                    access.RefreshExpDate = context.Ticket.Properties.ExpiresUtc.HasValue ? context.Ticket.Properties.ExpiresUtc.Value.LocalDateTime : DateTime.Now.AddSeconds(AppConstNum.refresh_expires_second);
                    access.Ticket = ticket;
                    //token持久化
                    var num = refreshToken == null ? await db.AddToken(access, responseType) : await db.UpdateToken(refreshToken.AccessTokenId, access);
                    if (num > 0)
                    {
                        context.SetToken(token);
                        await base.CreateAsync(context);
                    }
                    else
                    {
                        await Task.FromResult<object>(null);
                        return;
                    }
                }
            }
            catch
            {
                throw new AggregateException("生成刷新Token失败");
            }
        }

        public override async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            if (string.IsNullOrEmpty(context.Token))
            {
                await Task.FromResult<object>(null);
                return;
            }
            try
            {
                using (var db = new DbOAuthHelper())
                {
                    var token = await db.GetOAuthToken(context.Token);
                    if (token == null)
                    {
                        await Task.FromResult<object>(null);
                        return;
                    }
                    var elapsedTicks = (DateTime.Now.Ticks - token.RefreshExpDate.Ticks);
                    var elapsedSpan = new TimeSpan(elapsedTicks);
                    //验证refresh-token失效时间
                    if (elapsedSpan.TotalSeconds >= 0)
                    {
                        await Task.FromResult<object>(null);
                        return;
                    }
                    context.DeserializeTicket(token.Ticket);
                    if (context.Ticket != null)
                    {
                        context.SetTicket(context.Ticket);
                        //原先token数据
                        context.OwinContext.Set(OwinEnvType.RefreshToken, token);
                    }
                }
            }
            catch
            {
                throw new AggregateException("验证刷新Token失败");
            }
        }
    }
}